/***************************************************************************
 * This code is an original creation. It is intended to be used for a one  *
 * reader, one card situation within the Micro Framework. This is intended *
 * to be used with the GemCore Serial Lite Pro evaluation board or the     *
 * Teridian 73S1209F evaluation board, unless a device class is created    *
 * to work with another evaluation board.                                  *
 * LAST MODIFIED: 2010 April 23                                            *
 * Copyright (C) 2009 Gemalto                                              *
 ***************************************************************************/
/***************************************************************************
 *  Program.cs is part of the PC/SC Micro API for the .NET Micro           *
 *  Framework.                                                             *
 *                                                                         *
 *  The PC/SC Micro API for the .NET Micro Framework is free software:     *
 *  you can redistribute it and/or modify it under the terms of the GNU    *
 *  General Public License as published by the Free Software Foundation,   *
 *  either version 2 of the License, or (at your option) any later version.*
 *                                                                         *
 *  The PC/SC Micro API for the .NET Micro Framework is distributed in     *
 *  the hope that it will be useful, but WITHOUT ANY WARRANTY; without even*
 *  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR    *
 *  PURPOSE.  See the GNU General Public License for more details.         *
 *                                                                         *
 *  You should have received a copy of the GNU General Public License      *
 *  along with the PC/SC Micro API for the .NET Micro Framework. If not,   *
 *  see <http://www.gnu.org/licenses/>.                                    *
 ***************************************************************************/
using System;
using System.Threading;
using System.IO;
using System.Resources;
using System.Text;

using Microsoft.SPOT;
using Microsoft.SPOT.Cryptography;
using Microsoft.SPOT.Hardware;
using Microsoft.SPOT.Input;
using Microsoft.SPOT.Presentation;
using Microsoft.SPOT.Presentation.Controls;
using Microsoft.SPOT.Presentation.Media;
using Microsoft.SPOT.Presentation.Shapes;
using Microsoft.SPOT.IO;
using Microsoft.SPOT.Touch;

using PCSCMicro;
using TestSuite;

namespace FileSignature
{
    // Button Class
    public class ScreenButton : UIElement
    {

        // Autosizing constructor
        public ScreenButton(string caption, Font font)
        {
            _caption = caption;
            _font = font;
            HorizontalAlignment = HorizontalAlignment.Center;
            VerticalAlignment = VerticalAlignment.Center;
            int textWidth;
            int textHeight;
            _font.ComputeExtent(_caption, out textWidth, out textHeight);

            _width = textWidth + _textMarginX * 2;
            _height = textHeight + _textMarginY * 2;
        }

        // Manual sizing constructor
        public ScreenButton(string caption, Font font, int width, int height)
        {
            _width = width;
            _height = height;
            _caption = caption;
            _font = font;
            int textWidth;
            int textHeight;
            _font.ComputeExtent(_caption, out textWidth, out textHeight);
            _textMarginY = (height - textHeight) / 2;
            _textMarginX = (width - textWidth) / 2;
        }

        // Override OnRender to do our own drawing
        public override void OnRender(DrawingContext dc)
        {
            int x;
            int y;

            SolidColorBrush brush;
            Pen pen;
            Color color;
            Pen shade1;
            Pen shade2;

            // Check the pressed state and draw accordingly
            if (_pressed)
            {
                brush = _pressedBackgroundBrush;
                pen = _pressedBorderPen;
                color = _pressedForeColor;
                shade1 = _darkShade;
                shade2 = _lightShade;
            }
            else
            {
                brush = _normalBackgroundBrush;
                pen = _borderPen;
                color = _foreColor;
                shade1 = _lightShade;
                shade2 = _darkShade;
            }

            GetLayoutOffset(out x, out y);

            // Draw the base rectangle of the button
            dc.DrawRectangle(brush, pen, 1, 1, _width - 1, _height - 1);

            // Draw the caption
            string caption = _caption;
            dc.DrawText(ref caption, _font, color, 0, _textMarginY, _width, _height, _alignment, _trimming);

            // Shade the outline of the rectangle for classic button look
            dc.DrawLine(shade1, 1, 1, _width - 1, 1);
            dc.DrawLine(shade1, 1, 1, 1, _height - 1);
            dc.DrawLine(shade2, _width - 1, 1, _width - 1, _height - 1);
            dc.DrawLine(shade2, 1, _height - 1, _width - 1, _height - 1);
        }

        public event EventHandler Click;

        public bool Pressed
        {
            get
            {
                return _pressed;
            }
        }

        // Handle the stylus down event
        protected override void OnStylusDown(StylusEventArgs e)
        {

            // Flag for drawing state
            _pressed = true;

            // Capture the stylus
            Stylus.Capture(this);

            // Trigger redraw
            Invalidate();
        }

        // Handle the stylus up event
        protected override void OnStylusUp(StylusEventArgs e)
        {

            // Flag for drawing state
            _pressed = false;

            // Release the stylus
            Stylus.Capture(this, CaptureMode.None);

            // Trigger redraw
            Invalidate();

            // Fire a click event
            EventArgs args = new EventArgs();
            OnClick(args);
        }

        // Handle the stylus move....don't do anything special
        protected override void OnStylusMove(StylusEventArgs e)
        {

        }

        // Our click event
        protected virtual void OnClick(EventArgs e)
        {
            if (Click != null)
            {
                Click(this, e);
            }
        }

        protected override void ArrangeOverride(int arrangeWidth, int arrangeHeight)
        {

        }

        protected override void MeasureOverride(int availableWidth, int availableHeight, out int desiredWidth, out int desiredHeight)
        {
            desiredWidth = (availableWidth > _width) ? _width : availableWidth;
            desiredHeight = (availableHeight > _height) ? _height : availableHeight;
        }

        public string Caption
        {
            get
            {
                return _caption;
            }
            set
            {
                _caption = value;
            }
        }

        SolidColorBrush _normalBackgroundBrush = new SolidColorBrush(ColorUtility.ColorFromRGB(192, 192, 192));
        SolidColorBrush _pressedBackgroundBrush = new SolidColorBrush(ColorUtility.ColorFromRGB(128, 128, 128));

        Pen _borderPen = new Pen(ColorUtility.ColorFromRGB(128, 128, 128));

        Pen _pressedBorderPen = new Pen(ColorUtility.ColorFromRGB(128, 128, 128));

        Pen _lightShade = new Pen(ColorUtility.ColorFromRGB(216, 216, 216));
        Pen _darkShade = new Pen(ColorUtility.ColorFromRGB(64, 64, 64));

        int _width;
        int _height;
        string _caption = "";
        Font _font = null;
        Color _foreColor = ColorUtility.ColorFromRGB(0, 0, 0);
        Color _pressedForeColor = ColorUtility.ColorFromRGB(255, 255, 255);
        TextTrimming _trimming = TextTrimming.WordEllipsis;
        TextAlignment _alignment = TextAlignment.Center;
        protected int _textMarginX = 16;
        protected int _textMarginY = 8;
        protected bool _pressed = false;
    }

    // ***********************************************************************
    public class Program : Microsoft.SPOT.Application
    {
        public static void Main()
        {
            myApplication = new Program();
            Program.CreateWindow();
            // Initialize the touch screen
            Microsoft.SPOT.Touch.Touch.Initialize(myApplication);
            // Initialize the timer
            timer = new DispatcherTimer(myApplication.Dispatcher);
            timer.Tick += new EventHandler(timer_Tick);
            // Start the application
            myApplication.Run(mainWindow);
            // When application ends, power down card and reader
            SCard.Disconnect(card, SCardDisposition.UNPOWER_CARD);
            SCard.ReleaseContext(context);
        }

        #region Global Variables
        // Application and display variables
        static Program myApplication;
        static Window mainWindow;
        static Panel panel;
        static Text pinText;
        static Image img;
        static Bitmap bit;
        static Thread hashingThread;
        static string hashedImage;
        
        // Event related objects
        static DispatcherTimer timer;
        static ScreenButton Test;
        static ScreenButton Continue;
        static Thread PushedButton;
        
        // PC/SC Micro values
        static SCardHandle card;
        static SCardContext context;

        // Crypto data
        static string signature;
        static BigInteger Signat;
        static BigInteger Encoded;
        static byte[] exp, mod;
        
        // PIN data
        const string pinRequest = "Enter PIN:\n ";
        static string pin = "";
        
        // Counters and flags
        static int counter = 1;
        static int SignStep = 0;
        static bool NumDisplay = false;
        #endregion

        #region Communicate with Card
        /// <summary>
        /// Connect to reader to start application
        /// </summary>
        /// <remarks>
        /// If card is in error, exit application. If card is not present
        /// the wait for it to become present, then connect to reader.
        /// </remarks>
        /// <returns>True if reader connects, false otherwise</returns>
        static bool start()
        {
            // Get current status, return if error occurs
            SCardStatusReturn status = SCard.GetStatusChange(context, 0);
            SCardState state = status.State;
            if (SCard.GetError() != SCardError.SCARD_S_SUCCESS)
            {
                return false;
            }
            // If card is activated, try to deactivate
            if (state == SCardState.ACTIVATED)
            {
                SCard.ReleaseContext(context);
                if (SCard.GetError() != SCardError.SCARD_S_SUCCESS)
                {
                    return false;
                }
                context = SCard.EstablishContext();
                if (SCard.GetError() != SCardError.SCARD_S_SUCCESS)
                {
                    return false;
                }
                // Get new card status
                status = SCard.GetStatusChange(context, 0);
                if (SCard.GetError() != SCardError.SCARD_S_SUCCESS)
                {
                    return false;
                }
                state = status.State;
            }
            // If status is not present
            if (state != SCardState.PRESENT)
            {
                // If status is error, try to Reconnect to card
                if (state == SCardState.ERROR)
                {
                    SCard.Reconnect(card, SCardShareMode.SHARED, SCardProtocol.T0, SCardDisposition.RESET_CARD);
                    // If Reconnect fails, try to Disconnect card
                    if (SCard.GetError() != SCardError.SCARD_S_SUCCESS)
                    {
                        SCard.Disconnect(card, SCardDisposition.UNPOWER_CARD);
                        // If disconnect fails, exit applicaiton
                        if (SCard.GetError() == SCardError.SCARD_E_INVALID_HANDLE)
                        {
                            myApplication.Shutdown();
                        }
                        return false;
                    }
                }
                // If card is absent, wait for user to insert card
                else
                {
                    SCard.GetStatusChange(context, SCard.INFINITE);
                    if (SCard.GetError() != SCardError.SCARD_S_SUCCESS)
                    {
                        return false;
                    }
                }
            }
            // Card must be present (or activated) to reach here, so connect it
            card = SCard.Connect(context, SCardShareMode.SHARED, SCardProtocol.T0);
            if (SCard.GetError() == SCardError.SCARD_S_SUCCESS)
            {
                return true;
            }
            else 
            {
                return false;
            }
        }

        /// <summary>
        /// Verify Smart Card PIN
        /// </summary>
        /// <param name="PIN">PIN entered by user</param>
        /// <returns>True if PIN is correct, false otherwise</returns>
        static bool verifyPin(byte[] PIN)
        {
            // Must have PIN to verify
            if (PIN.Length == 0)
            {
                return false;
            }
            // Create command strings
            string envelopeCommand = "80C20000";
            string command = "D800056F00C04B4E7FBD506B00044D53434D01000000";
            pin = HexStringDecoder.ByteArrayToString(PIN, PIN.Length);
            string PINLength = HexStringDecoder.ByteToHex((byte)(pin.Length / 2));
            string len = HexStringDecoder.ByteToHex((byte)(command.Length / 2 + pin.Length / 2 + PINLength.Length / 2));
            // Begin transaction and transmit command
            SCard.BeginTransaction(card);
            if (SCard.GetError() != SCardError.SCARD_S_SUCCESS)
            {
                return false;
            }
            string response = SCard.Transmit(card, SCardProtocol.T0, envelopeCommand + len + command + PINLength + pin);
            if (SCard.GetError() != SCardError.SCARD_S_SUCCESS)
            {
                SCard.EndTransaction(card, SCardDisposition.LEAVE_CARD);
                return false;
            }
            // If response is successful response return true, otherwise false
            if (response.Equals("9000"))
            {
                SCard.EndTransaction(card, SCardDisposition.LEAVE_CARD);
                return true;
            }
            SCard.EndTransaction(card, SCardDisposition.LEAVE_CARD);
            return false;
        }

        /// <summary>
        /// Digitally sign data in message
        /// </summary>
        /// <remarks>
        /// Signature of message is placed into variable "signature". If
        /// signature fails, then "signature" = "";
        /// </remarks>
        /// <param name="message">Data to sign</param>
        static void sign(string message)
        {
            // Initialize signature
            signature = "";
            // Create command strings
            string envelopeCommand = "80C20000";
            string command = "D800056F00C04B4E7FBD614400044D53434D0002000000";
            string length = HexStringDecoder.ByteToHex((byte)(message.Length / 2));
            string len = HexStringDecoder.ByteToHex((byte)(command.Length / 2 + length.Length / 2 + message.Length / 2));
            // Begin transaction and transmit command
            SCard.BeginTransaction(card);
            if (SCard.GetError() != SCardError.SCARD_S_SUCCESS)
            {
                return;
            }
            string response = SCard.Transmit(card, SCardProtocol.T0,
                             envelopeCommand + len + command + length + message);
            if (SCard.GetError() != SCardError.SCARD_S_SUCCESS)
            {
                return;
            }
            // If response indicates it has bytes waiting, access them
            if (response.Substring(0, 2).Equals("61"))
            {
                string apduMessage = "00C00000" + response.Substring(2, 2);
                string response2 = SCard.Transmit(card, SCardProtocol.T0, apduMessage);
                if (SCard.GetError() != SCardError.SCARD_S_SUCCESS)
                {
                    return;
                }
                // If second response has success status word, set signature
                if (response2.Length >= 24 && response2.Substring(response2.Length - 4).Equals("9000"))
                {
                    signature = response2.Substring(20, response2.Length - 20 - 4);
                }
            }
            SCard.EndTransaction(card, SCardDisposition.LEAVE_CARD);
        }

        /// <summary>
        /// Get public key from Smart Card
        /// </summary>
        /// <remarks>
        /// Once public key is obtained, parseme() is called to place
        /// modulus into byte array mod and exponent into byte array exp.
        /// </remarks>
        static void publicKey()
        {
            // Create command string
            byte[] apduCmd = { 0x80, 0xC2, 0x00, 0x00, 0x13, 0xD8, 0x00, 0x05, 0x6F, 0x00,
                                       0xC0, 0x4B, 0x4E, 0x7F, 0xBD, 0x9B, 0x2E, 0x00, 0x04, 0x4D,
                                       0x53, 0x43, 0x4D, 0x00 };
            // Begin Transaction and transmit command
            SCard.BeginTransaction(card);
            if (SCard.GetError() != SCardError.SCARD_S_SUCCESS)
            {
                return;
            }
            string response = SCard.Transmit(card, SCardProtocol.T0, HexStringDecoder.ByteArrayToString(apduCmd, apduCmd.Length));
            if (SCard.GetError() != SCardError.SCARD_S_SUCCESS)
            {
                SCard.EndTransaction(card, SCardDisposition.LEAVE_CARD);
                return;
            }
            // If response indicates it has bytes waiting, access them
            if (response.Substring(0, 2).Equals("61"))
            {
                string apduMessage = "00C00000" + response.Substring(2, 2);
                string response2 = SCard.Transmit(card, SCardProtocol.T0, apduMessage);
                if (SCard.GetError() != SCardError.SCARD_S_SUCCESS)
                {
                    SCard.EndTransaction(card, SCardDisposition.LEAVE_CARD);
                    return;
                }
                // If second response has success status word, parse response
                if (response2.Substring(response2.Length - 4).Equals("9000"))
                {
                    string parseme = response2.Substring(20, response2.Length - 20 - 4);
                    parse(parseme);
                }
            }
            SCard.EndTransaction(card, SCardDisposition.LEAVE_CARD);
        }

        /// <summary>
        /// Generates a new key pair on Smart Card
        /// </summary>
        /// <remarks>
        /// Public and private key are only known to Smart Card
        /// after this function is called. Public key can be obtained
        /// by calling publicKey(), but private key stays only known 
        /// by Smart Card.
        /// </remarks>
        static void keyPair()
        {
            // Create command string
            byte[] genKey = new byte[] {0x80, 0xC2, 0x00, 0x00, 0x1D, 0xD8, 0x00, 0x05,
                0x6F, 0x00, 0xC0, 0x4B, 0x4E, 0x7F, 0xBD, 0x02, 0x34, 0x00, 0x04, 0x4D,
                0x53, 0x43, 0x4D, 0x00, 0x00, 0x02, 0x00, 0x00, 0x04, 0x00, 0xFF, 0xFF,
                0xFF, 0xFF};
            // Begin transaction and transmit command
            SCard.BeginTransaction(card);
            if (SCard.GetError() != SCardError.SCARD_S_SUCCESS)
            {
                return;
            }
            string response = SCard.Transmit(card, SCardProtocol.T0, HexStringDecoder.ByteArrayToString(genKey, genKey.Length));
            // No need to handle response, as user is oblivious to result
            SCard.EndTransaction(card, SCardDisposition.LEAVE_CARD);
        }
        
        /// <summary>
        /// Gets number of PIN tries left
        /// </summary>
        /// <remarks>
        /// If number of PIN tries left is 0, then the card has blocked
        /// itself and user must exit application and unblock card.
        /// </remarks>
        /// <returns>Number of PIN tries left</returns>
        static int GetTries()
        {
            // Initialize number of PIN tries
            int tries = 0;
            // Create command string
            byte[] genKey = new byte[] { 0x80, 0xC2, 0x00, 0x00, 0x13, 0xD8, 0x00, 
                0x05, 0x6F, 0x00, 0xC0, 0x4B, 0x4E, 0x7F, 0xBD, 0x6D, 0x08, 0x00, 
                0x04, 0x4D, 0x53, 0x43, 0x4D, 0x01 };
            // Begin transaction and transmit command
            SCard.BeginTransaction(card);
            if (SCard.GetError() != SCardError.SCARD_S_SUCCESS)
            {
                return tries;
            }
            string response = SCard.Transmit(card, SCardProtocol.T0, HexStringDecoder.ByteArrayToString(genKey, genKey.Length));
            if (SCard.GetError() != SCardError.SCARD_S_SUCCESS)
            {
                SCard.EndTransaction(card, SCardDisposition.LEAVE_CARD);
                return tries;
            }
            // If response indicates it has bytes waiting, access them
            if (response.Substring(0, 2).Equals("61"))
            {
                string apduMessage = "00C00000" + response.Substring(2, 2);
                string response2 = SCard.Transmit(card, SCardProtocol.T0, apduMessage);
                // If second response has success status word, parse response
                if (response2.Substring(20).Equals("9000"))
                {
                    tries = int.Parse(response2.Substring(18, 2));
                }
            }
            SCard.EndTransaction(card, SCardDisposition.LEAVE_CARD);
            return tries;
        }

        #endregion

        #region Other
        /// <summary>
        /// Parse response into exponent and modulus byte arrays
        /// </summary>
        /// <param name="parseme">String containing card response to
        /// obtaining public key</param>
        static void parse(string parseme)
        {
            byte[] keyData = HexStringDecoder.StringToByteArray(parseme);
            // Extract the exponent length, index of modulus, and modulus length
            int exponentLength = keyData[4];
            int modulusIndex = 7 + exponentLength;
            int modulusSize = keyData.Length - modulusIndex;
            // Parse modulus from keyData
            mod = new byte[modulusSize];
            for (int i = 0; i < modulusSize; i++)
            {
                mod[i] = keyData[i + modulusIndex];
            }
            // If modulus does not equal indicated value, then set to null
            if ((mod.Length >> 4) != keyData[modulusIndex - 1])
            {
                mod = null;
            }
            // If modulus is correct, parse exponent from keyData
            else
            {
                exp = new byte[exponentLength];
                for (int i = 0; i < exponentLength; i++)
                {
                    exp[i] = keyData[5 + i];
                }
            }
        }

        /// <summary>
        /// Pad and encode hashValue for sigining
        /// </summary>
        /// <param name="hashValue">Hash value to be padded</param>
        /// <returns>Padded hash value encoded for sigining</returns>
        static string encodeHashForSigningSHA1(string hashValue)
        {
            // Add padding constant to hash value
            string SHA_DER_Encoded = "3021300906052B0E03021A05000414";
            string message_to_sign = SHA_DER_Encoded + hashValue;
            // Generate padding string according to modulus length
            int pad_len = mod.Length - message_to_sign.Length / 2;
            string Padding_PS = "";
            for (int i = 0; i < pad_len - 3; i++)
            {
                Padding_PS += "FF";
            }
            string new_message_to_sign_str = "0001" + Padding_PS + "00";
            // Prepare padding string and hash value for padding
            byte[] new_message_to_sign_arr = HexStringDecoder.StringToByteArray(new_message_to_sign_str);
            int len1 = new_message_to_sign_arr.Length;
            byte[] msg_to_sign_arr = HexStringDecoder.StringToByteArray(message_to_sign);
            int len2 = msg_to_sign_arr.Length;
            // Pad hash value by first adding padded string
            byte[] new_message_to_sign = new byte[len1 + len2];
            for (int i = 0; i < len1; i++)
            {
                new_message_to_sign[i] = new_message_to_sign_arr[i];
            }
            // Then hash add padding constant
            for (int i = 0; i < len2; i++)
            {
                new_message_to_sign[len1 + i] = msg_to_sign_arr[i];
            }
            return HexStringDecoder.ByteArrayToString(new_message_to_sign, new_message_to_sign.Length);
        }

        /// <summary>
        /// Hash image function to be called in separate thread
        /// </summary>
        static void HashImage()
        {
            hashedImage = SHA1.Hash(bit.GetBitmap());
        }

        /// <summary>
        /// Initialize window for display
        /// </summary>
        static void CreateWindow()
        {
            // Create a window object and set its size to the size of the display.
            mainWindow = new Window();
            mainWindow.Height = SystemMetrics.ScreenHeight;
            mainWindow.Width = SystemMetrics.ScreenWidth;
            try
            {
                // panel control to fill the window client area
                panel = new Panel();
                panel.HorizontalAlignment = HorizontalAlignment.Stretch;
                panel.VerticalAlignment = VerticalAlignment.Stretch;
                // Generate a bitmap and obtain from the resource
                Bitmap original = Resources.GetBitmap(Resources.BitmapResources.SmartBadge2D);
                // Resize the image
                Bitmap resized = new Bitmap(mainWindow.Width, mainWindow.Height);
                resized.StretchImage(0, 0, original, resized.Width, resized.Height, 255);
                // Prepare bitmap for hashing, set bit to whichever is smaller
                if (original.Width * original.Height > resized.Height * resized.Width)
                {
                    bit = resized;
                }
                else
                {
                    bit = original;
                }
                img = new Image(resized);
                // Hash image in background
                hashingThread = new Thread(new ThreadStart(HashImage));
                hashingThread.Start();
            }
            // If image is too large
            catch (OutOfMemoryException)
            {
                pinText.TextContent = "Image too large to open (must be < 1MB)";
            }
            catch (Exception)
            {
                pinText.TextContent = "Unknown error, maybe image doesn't exist?";
            }
            // Generate application start button
            ScreenButton startButton = new ScreenButton("Push to start application",
                Resources.GetFont(Resources.FontResources.NinaB));
            startButton.VerticalAlignment = VerticalAlignment.Bottom;
            startButton.Click += new EventHandler(startButton_Click);
            panel.Children.Add(startButton);
            // Add the text control to the window.
            mainWindow.Child = panel;
            mainWindow.Background = new SolidColorBrush(Color.Black);
            // Set the window visibility to visible.
            mainWindow.Visibility = Visibility.Visible;
            // Attach the button focus to the window.
            Buttons.Focus(mainWindow);
        }

        /// <summary>
        /// Function to do signing in background to save time.
        /// </summary>
        /// <remarks>
        ///  Counter is updated after every call to signal ready for display.
        /// </remarks>
        static void Sign()
        {
            // Generate key pair
            counter = 0;
            SignStep = 0;
            keyPair();
            counter++;
            // Obtain public key
            publicKey();
            counter++;
            // Sign image
            sign(encodeHashForSigningSHA1(hashedImage));
            counter++;
        }
        #endregion

        #region Button Generation
        /// <summary>
        /// Generate buttons to run or skip test suite
        /// </summary>
        static void GenerateTestButton()
        {
            // Generate run test suite button
            Test = new ScreenButton("Run Test Suite",
                Resources.GetFont(Resources.FontResources.NinaB));
            Test.VerticalAlignment = VerticalAlignment.Bottom;
            Test.HorizontalAlignment = HorizontalAlignment.Left;
            Test.Click += new EventHandler(Test_Click);
            // Generage skip test suite button
            ScreenButton PIN = new ScreenButton("Skip Test Suite",
                Resources.GetFont(Resources.FontResources.NinaB));
            PIN.VerticalAlignment = VerticalAlignment.Bottom;
            PIN.HorizontalAlignment = HorizontalAlignment.Right;
            PIN.Click += new EventHandler(PIN_Click);
            // Update pinText
            pinText = new Text(Resources.GetFont(Resources.FontResources.NinaB), "");
            pinText.ForeColor = Color.White;
            pinText.HorizontalAlignment = HorizontalAlignment.Center;
            pinText.VerticalAlignment = VerticalAlignment.Top;
            pinText.TextWrap = true;
            // Display everything to screen
            panel.Children.Add(pinText);
            panel.Children.Add(Test);
            panel.Children.Add(PIN);
        }

        /// <summary>
        /// Generate PIN pad for PIN entry
        /// </summary>
        static void GeneratePINButtons()
        {
            // Initialize PIN 
            pin = "";
            // Remove everything from screen
            panel.Children.Clear();
            // Set button width and height
            int Width = 106;
            int Height = 50;
            // Create canvas for manual display placement
            Canvas canvas = new Canvas();
            canvas.HorizontalAlignment = HorizontalAlignment.Stretch;
            canvas.VerticalAlignment = VerticalAlignment.Stretch;
            panel.Children.Add(canvas);
            int counter = 9;
            // Generate 1-9 buttons
            for (int y = 0; y < 3; y++)
            {
                for (int x = 2; x >= 0; x--)
                {
                    ScreenButton button = new ScreenButton(counter--.ToString(),
                        Resources.GetFont(Resources.FontResources.NinaB), Width, Height);
                    button.Click += new EventHandler(buttonNum_Click);
                    Canvas.SetLeft(button, x * Width + 1);
                    Canvas.SetTop(button, y * Height + 39);
                    canvas.Children.Add(button);
                }
            }
            // Generate Enter, Back, and 0 buttons
            for (int x = 2; x >= 0; x--)
            {
                ScreenButton button;
                if (x == 2)
                {
                    button = new ScreenButton("Enter",
                        Resources.GetFont(Resources.FontResources.NinaB), Width, Height);
                    button.Click += new EventHandler(buttonEnter_Click);
                }
                else if (x == 1)
                {
                    button = new ScreenButton("0",
                        Resources.GetFont(Resources.FontResources.NinaB), Width, Height);
                    button.Click += new EventHandler(buttonNum_Click);
                }
                else
                {
                    button = new ScreenButton("Back",
                        Resources.GetFont(Resources.FontResources.NinaB), Width, Height);
                    button.Click += new EventHandler(buttonBack_Click);
                }
                Canvas.SetLeft(button, x * Width + 1);
                Canvas.SetTop(button, 3 * Height + 39);
                canvas.Children.Add(button);
            }
            // Update and display pinText
            pinText.TextContent = pinRequest + pin;
            pinText.VerticalAlignment = VerticalAlignment.Top;
            panel.Children.Add(pinText);
            // Initialize timer for hidden PIN entry display
            timer.Interval = new TimeSpan(0, 0, 0, 0, 250);
            if (timer.IsEnabled)
            {
                timer.Stop();
            }
            // Set flag for timer
            NumDisplay = true;
        }

        /// <summary>
        /// Remove PIN pad from screen
        /// </summary>
        static void RemovePINButtons()
        {
            // Remove timer flag and PIN buttons
            NumDisplay = false;
            panel.Children.Clear();
            panel.Children.Add(pinText);
        }

        /// <summary>
        /// Generate and display continue button
        /// </summary>
        static void GenerateContinueButton()
        {
            // Generate continue button
            Continue = new ScreenButton("Continue",
                Resources.GetFont(Resources.FontResources.NinaB));
            Continue.VerticalAlignment = VerticalAlignment.Bottom;
            Continue.HorizontalAlignment = HorizontalAlignment.Center;
            Continue.Click += new EventHandler(Continue_Click);
            // Generate a bitmap and obtain from the resource
            Bitmap original = Resources.GetBitmap(Resources.BitmapResources.CheckMarkGreen);
            // Resize the image
            Bitmap resized = new Bitmap(mainWindow.Width, mainWindow.Height);
            resized.StretchImage(0, 0, original, resized.Width, resized.Height, 255);
            // Place in image object for display
            Image img = new Image(resized);
            img.VerticalAlignment = VerticalAlignment.Center;
            img.HorizontalAlignment = HorizontalAlignment.Center;
            // Update display
            panel.Children.Clear();
            pinText.VerticalAlignment = VerticalAlignment.Center;
            pinText.ForeColor = Color.Black;
            panel.Children.Add(img);
            panel.Children.Add(pinText);
            panel.Children.Add(Continue);
        }

        /// <summary>
        /// Generate buttons to use after verification image
        /// </summary>
        static void GenerateAfterVerifyButtons()
        {
            // Display run test suite button
            panel.Children.Add(Test);
            // Configure and display continue button
            Continue.Caption = "Continue";
            Continue.HorizontalAlignment = HorizontalAlignment.Right;
            panel.Children.Add(Continue);
            // Reset pinText and counter
            pinText.TextContent = "";
            counter = 0;
        }
        #endregion

        #region Events
        /// <summary>
        /// Handle timer tick event
        /// </summary>
        /// <remarks>
        /// Timer tick events are used to display information about the
        /// test while the test suite is running. It is also used to 
        /// change the PIN pad into stars shortly after each button is 
        /// pressed.
        /// </remarks>
        /// <param name="sender">Sender that sparked event</param>
        /// <param name="e">Event arguments</param>
        static void timer_Tick(object sender, EventArgs e)
        {
            // If timer is being used for test suite
            if (!NumDisplay)
            {
                // If test suite has not finished yet
                if (PushedButton.IsAlive)
                {
                    // If test suite is ready to update screen
                    if (APITestSuite.DisplayToScreen)
                    {
                        // If most recent information was not a passed test, ignore it
                        // Used to ignore "All ... tests passed" second time around
                        if (APITestSuite.Test2Info.Substring(0, 3).Equals("All"))
                        {
                            pinText.TextContent = "";
                        }
                        // If first test, display initial information
                        else if (counter == 0)
                        {
                            pinText.TextContent = APITestSuite.Test2Info;
                            counter++;
                        }
                        // Otherwise describe passed test with test number
                        else
                        {
                            pinText.TextContent = "Test " + counter++.ToString()
                                                + " passed which tested\n" + APITestSuite.Test2Info;
                        }
                        // If current information is not test, display only information
                        if (APITestSuite.TestInfo.Substring(0, 3).Equals("All"))
                        {
                            pinText.TextContent += "\n\n" + APITestSuite.TestInfo;
                        }
                        // Otherwise describe current test with test number
                        else
                        {
                            pinText.TextContent += "\n\nRunning test " + counter.ToString()
                                               + " which tests\n" + APITestSuite.TestInfo;
                        }
                        // Update progress bar and display flag
                        panel.Children[panel.Children.Count - 1].Width = 320 * counter / 23;
                        APITestSuite.DisplayToScreen = false;
                    }
                }
                // If all tests have been passed
                else if (APITestSuite.TestInfo == "All tests passed")
                {
                    // Start up reader
                    context = SCard.EstablishContext();
                    while (SCard.GetError() != SCardError.SCARD_S_SUCCESS)
                    {
                        SCard.ReleaseContext(context);
                        context = SCard.EstablishContext();
                    }
                    // Connect smart card
                    while (!start()) ;
                    // Display PIN pad and reset counter
                    GeneratePINButtons();
                    counter = 0;
                }
                // If test has failed
                else
                {
                    // Get error, display fail information and exit application
                    SCardError err = SCard.GetError();
                    pinText.TextContent = "Test " + counter.ToString() + " failed which tested\n"
                                        + APITestSuite.TestInfo + "\nExiting application"
                                        + "\nError: " + SCard.StringifyError(err);
                    myApplication.Shutdown();
                }
            }
            // If PIN pad timer
            else
            {
                // Display the PIN as stars and stop timer
                if (pin.Length > 0)
                {
                    pinText.TextContent = pinRequest;
                    for (int i = 0; i < pin.Length; i++)
                    {
                        pinText.TextContent += "*";
                    }
                }
                timer.Stop();
            }
        }

        /// <summary>
        /// Handle PIN button click event
        /// </summary>
        /// <remarks>
        /// PIN button is used to generate the PIN pad
        /// </remarks>
        /// <param name="sender">Sender that sparked event</param>
        /// <param name="e">Event arguments</param>
        static void PIN_Click(object sender, EventArgs e)
        {
            // Start up reader
            context = SCard.EstablishContext();
            while (SCard.GetError() != SCardError.SCARD_S_SUCCESS)
            {
                SCard.ReleaseContext(context);
                context = SCard.EstablishContext();
            }
            // Connect smart card and generate PIN pad
            while (!start()) ;
            GeneratePINButtons();
        }

        /// <summary>
        /// Handle Test button click event
        /// </summary>
        /// <remarks>
        /// Test button is used to set up and run the test suite
        /// </remarks>
        /// <param name="sender">Sender that sparked event</param>
        /// <param name="e">Event arguments</param>
        static void Test_Click(object sender, EventArgs e)
        {
            // Update display information
            panel.Children.Clear();
            panel.Children.Add(pinText);
            pinText.HorizontalAlignment = HorizontalAlignment.Center;
            pinText.VerticalAlignment = VerticalAlignment.Center;
            // Create progress bar
            Rectangle rect = new Rectangle();
            rect.Stroke.Color = ColorUtility.ColorFromRGB(0, 255, 0);
            rect.Fill = new SolidColorBrush(ColorUtility.ColorFromRGB(0, 255, 0));
            rect.Width = 0;
            rect.Height = 15;
            rect.HorizontalAlignment = HorizontalAlignment.Left;
            rect.VerticalAlignment = VerticalAlignment.Bottom;
            panel.Children.Add(rect);
            // Initialize counter and timer for testing
            counter = 0;
            timer.Interval = new TimeSpan(0, 0, 0, 0, 200);
            timer.Start();
            // Activate test suite in new thread
            PushedButton = new Thread(new ThreadStart(APITestSuite.ActivateTestSuite));
            PushedButton.Start();
        }

        /// <summary>
        /// Handle StartButton button click event
        /// </summary>
        /// <remarks>
        /// StartButton is used to initialize display of application and 
        /// generate buttons to run and to skip test suite
        /// </remarks>
        /// <param name="sender">Sender that sparked event</param>
        /// <param name="e">Event arguments</param>
        static void startButton_Click(object sender, EventArgs e)
        {
            // Clear display and generate run and skip test suite buttons
            panel.Children.Clear();
            GenerateTestButton();
        }

        /// <summary>
        /// Handle PIN pad number button click event
        /// </summary>
        /// <remarks>
        /// PIN pad number buttons are used to allow user to enter PIN
        /// </remarks>
        /// <param name="sender">Sender that sparked event</param>
        /// <param name="e">Event arguments</param>
        static void buttonNum_Click(object sender, EventArgs e)
        {
            // Stop timer if running
            timer.Stop();
            // If Invalid PIN message is being displayed, remove it
            if (pinText.TextContent.Substring(0, 1).Equals("I"))
            {
                pinText.TextContent = pinRequest;
            }
            // If most recent number is not a star, change it to a star
            if (!pinText.TextContent.Substring(pinText.TextContent.Length - 1, 1).Equals("*"))
            {
                if (pin.Length > 0)
                {
                    pinText.TextContent = pinRequest;
                    for (int i = 0; i < pin.Length; i++)
                    {
                        pinText.TextContent += "*";
                    }
                }
            }
            // Update pin according to button pushed
            pin += ((ScreenButton)sender).Caption;
            pinText.TextContent += ((ScreenButton)sender).Caption;
            // Start timer to display number for short time, then change to star
            timer.Start();
        }

        /// <summary>
        /// Handle PIN pad back button click event
        /// </summary>
        /// <remarks>
        /// PIN pad back button is used as backspace key in PIN pad
        /// </remarks>
        /// <param name="sender">Sender that sparked event</param>
        /// <param name="e">Event arguments</param>
        static void buttonBack_Click(object sender, EventArgs e)
        {
            // If number has been entered, remove last one
            if (pin != null && pin.Length > 0)
            {
                pin = pin.Substring(0, pin.Length - 1);
            }
            // Display pin as stars
            pinText.TextContent = pinRequest;
            for (int i = 0; i < pin.Length; i++)
            {
                pinText.TextContent += "*";
            }
        }

        /// <summary>
        /// Handle PIN pad enter button click event
        /// </summary>
        /// <remarks>
        /// PIN pad enter button is used to verify PIN
        /// </remarks>
        /// <param name="sender">Sender that sparked event</param>
        /// <param name="e">Event arguments</param>
        static void buttonEnter_Click(object sender, EventArgs e)
        {
            // Convert PIN into byte array
            char[] charArray = pin.ToCharArray();
            byte[] PIN = new byte[charArray.Length];
            for (int i = 0; i < PIN.Length; i++)
            {
                PIN[i] = (byte)charArray[i];
            }
            // If verification fails
            if (!verifyPin(PIN))
            {
                // Get number of tries left
                int numTries = GetTries();
                // If user has tries left display how many, otherwise exit application
                if (numTries > 0)
                {
                    pin = "";
                    pinText.TextContent = "Invalid PIN: " + numTries + " tries left\n " + pinRequest;
                }
                else
                {
                    pinText.TextContent = "Please Unblock PIN\nExiting Application";
                    myApplication.Shutdown();
                }
            }
            // If verification succeeds
            else
            {
                // Stop timer and update display
                timer.Stop();
                pinText.TextContent = "PIN was Correct";
                RemovePINButtons();
                GenerateContinueButton();
            }
        }

        /// <summary>
        /// Handle Continue button click event
        /// </summary>
        /// <remarks>
        /// Continue button is used first to continue after successful
        /// pin, but later used to exit application if user chooses to
        /// not sign image file displayed.
        /// </remarks>
        /// <param name="sender">Sender that sparked event</param>
        /// <param name="e">Event arguments</param>
        static void Continue_Click(object sender, EventArgs e)
        {
            // If button was acting as an exit application button
            if (Continue.Caption.Equals("Exit"))
            {
                // Update display to exiting application and exit application
                pinText.HorizontalAlignment = HorizontalAlignment.Center;
                pinText.VerticalAlignment = VerticalAlignment.Center;
                pinText.TextContent = "Exiting Application";
                panel.Children.Clear();
                panel.Children.Add(pinText);
                myApplication.Shutdown();
            }
            // If button was acting as continue button
            else
            {
                // Display image
                panel.Children.Clear();
                panel.Children.Add(img);
                panel.Children.Add(Continue);
                // Change continue button to exit application button
                Continue.Caption = "Exit";
                Continue.HorizontalAlignment = HorizontalAlignment.Left;
                // Generate sign button
                ScreenButton Sign = new ScreenButton("Sign",
                    Resources.GetFont(Resources.FontResources.NinaB),
                    Continue.ActualWidth, Continue.ActualHeight);
                Sign.VerticalAlignment = VerticalAlignment.Bottom;
                Sign.HorizontalAlignment = HorizontalAlignment.Right;
                Sign.Click += new EventHandler(Sign_Click);
                pinText.ForeColor = Color.White;
                panel.Children.Add(Sign);
                counter = 0;
                // Wait for image to stop hashing before continuing
                hashingThread.Join();
            }
        }

        /// <summary>
        /// Handle ShowImage button click event
        /// </summary>
        /// <remarks>
        /// ShowImage button is used to show the verification image after 
        /// signing and decoding signature, whether displaying a successful
        /// image or failed image
        /// </remarks>
        /// <param name="sender">Sender that sparked event</param>
        /// <param name="e">Event arguments</param>
        static void ShowImage_Click(object sender, EventArgs e)
        {
            panel.Children.Clear();
            // If signature is valid, display successful picture
            if (Signat.Equals(Encoded))
            {
                panel.Children.Add(img);
                Image SuccessImage = new Image(
                    Resources.GetBitmap(Resources.BitmapResources.CheckMarkGreen));
                SuccessImage.VerticalAlignment = VerticalAlignment.Center;
                SuccessImage.HorizontalAlignment = HorizontalAlignment.Center;
                panel.Children.Add(SuccessImage);
            }
            // If signature is invalid, display failed picture
            else
            {
                panel.Children.Add(img);
                Image FailImage = new Image(
                    Resources.GetBitmap(Resources.BitmapResources.X));
                FailImage.VerticalAlignment = VerticalAlignment.Center;
                FailImage.HorizontalAlignment = HorizontalAlignment.Center;
                panel.Children.Add(FailImage);
            }
            // Generate and display buttons for after verification
            GenerateAfterVerifyButtons();
        }

        /// <summary>
        /// Handle Verification button click event
        /// </summary>
        /// <remarks>
        /// Verification button is used to decode signature and display
        /// the resulting hex string
        /// </remarks>
        /// <param name="sender">Sender that sparked event</param>
        /// <param name="e">Event arguments</param>
        static void Verification_Click(object sender, EventArgs e)
        {
            panel.Children.Clear();
            panel.Children.Add(pinText);
            // Create original string for verification
            string encoded = encodeHashForSigningSHA1(hashedImage);
            // Set up variables for decoding and comparison
            byte[] sig = HexStringDecoder.StringToByteArray(signature);
            Signat = new BigInteger(sig);
            BigInteger Modul = new BigInteger(mod);
            Encoded = new BigInteger(HexStringDecoder.StringToByteArray(encoded));
            // Decode signature using public key
            Signat = Signat.modPow(new BigInteger(exp), Modul);
            //counter++;
            // Retrieve data from BigInteger signature
            byte[] data = Signat.getByteArray();
            for (int i = 0; i < 10; i++)
            {
                byte temp = data[i];
                data[i] = data[20 - i - 1];
                data[20 - i - 1] = temp;
            }
            // Generate show verificaion image button
            ScreenButton ShowImage = new ScreenButton("Show Verification Image",
                Resources.GetFont(Resources.FontResources.NinaB));
            ShowImage.HorizontalAlignment = HorizontalAlignment.Right;
            ShowImage.VerticalAlignment = VerticalAlignment.Bottom;
            ShowImage.Click += new EventHandler(ShowImage_Click);
            // Update display
            pinText.TextContent += "\nDecoded Signature:\n";
            pinText.TextContent += HexStringDecoder.ByteArrayToString(data, 20);
            panel.Children.Add(ShowImage);
            SignStep = 0;
        }

        /// <summary>
        /// Handle Corrupt signature button click event
        /// </summary>
        /// <remarks>
        /// Corrupt signature button is used as a simulation of a corrupt
        /// image file. If an image file is corrupt, then the hash function
        /// will not be correct when the signature is decoded. This is
        /// simulated by signing new data.
        /// </remarks>
        /// <param name="sender">Sender that sparked event</param>
        /// <param name="e">Event arguments</param>
        static void Corrupt_Click(object sender, EventArgs e)
        {
            // Remove corrupt signature button
            panel.Children.RemoveAt(panel.Children.Count - 1);
            // Generate new data to hash and sign
            char[] carr = "Hello World!".ToCharArray();
            byte[] data1 = new byte[carr.Length];
            for (int i = 0; i < data1.Length; i++)
            {
                data1[i] = (byte)carr[i];
            }
            // Hash and sign data and update display
            sign(encodeHashForSigningSHA1(SHA1.Hash(data1)));
            pinText.TextContent = "Corrupt Signature:\n" + signature
                + "\n\n Original Hash:\n" + hashedImage;
        }

        /// <summary>
        /// Handle Sign button click event
        /// </summary>
        /// <remarks>
        /// Sign button is used to initialize the signing sequence.
        /// </remarks>
        /// <param name="sender">Sender that sparked event</param>
        /// <param name="e">Event arguments</param>
        static void Sign_Click(object sender, EventArgs e)
        {
            // Update display
            panel.Children.Clear();
            panel.Children.Add(pinText);
            pinText.TextContent = "";
            pinText.VerticalAlignment = VerticalAlignment.Top;
            pinText.HorizontalAlignment = HorizontalAlignment.Left;
            // Generate view next detail button
            ScreenButton ViewDetail = new ScreenButton("View Next Detail", 
                Resources.GetFont(Resources.FontResources.NinaB));
            ViewDetail.VerticalAlignment = VerticalAlignment.Bottom;
            ViewDetail.HorizontalAlignment = HorizontalAlignment.Center;
            ViewDetail.Click += new EventHandler(VeiwDetail_Click);
            panel.Children.Add(ViewDetail);
            // Start signing process in background to save user time
            PushedButton = new Thread(new ThreadStart(Sign));
            PushedButton.Start();
        }

        /// <summary>
        /// Handle ViewDetail button click event
        /// </summary>
        /// <remarks>
        /// ViewDetail button is used to display details of the signing
        /// process to the screen one at a time for the user to see.
        /// </remarks>
        /// <param name="sender">Sender that sparked event</param>
        /// <param name="e">Event arguments</param>
        static void VeiwDetail_Click(object sender, EventArgs e)
        {
            // Wait for next detail to be ready to display
            while (counter <= SignStep) ;
            SignStep++;
            // Determine how far in signing process application is
            switch (SignStep)
            {
                // Should never reach this case.
                case 0:
                    break;
                // If key pair was just generated, display information
                case 1:
                    pinText.TextContent = "New Key Pair Generated";
                    break;
                // If public key was just recieved, display public key and hash
                case 2:
                    pinText.TextContent += "\nExponent:\n" + HexStringDecoder.ByteArrayToString(exp, exp.Length);
                    pinText.TextContent += "\nModulus:\n" + HexStringDecoder.ByteArrayToString(mod, mod.Length);
                    pinText.TextContent += "\n\nOriginal Hash:\n" + hashedImage;
                    break;
                // If signature was just generated
                case 3:
                    // Display signature
                    pinText.TextContent = "Signature:\n" + signature
                                         + "\n\nOriginal Hash:\n" + hashedImage;
                    // Generate Corrupt signature button
                    ScreenButton Corrupt = new ScreenButton("Corrupt Signature",
                        Resources.GetFont(Resources.FontResources.NinaB));
                    Corrupt.HorizontalAlignment = HorizontalAlignment.Left;
                    Corrupt.VerticalAlignment = VerticalAlignment.Bottom;
                    Corrupt.Click += new EventHandler(Corrupt_Click);
                    // Generate Decode signature button
                    ScreenButton Verification = new ScreenButton("Decode Signature",
                        Resources.GetFont(Resources.FontResources.NinaB));
                    Verification.HorizontalAlignment = HorizontalAlignment.Right;
                    Verification.VerticalAlignment = VerticalAlignment.Bottom;
                    Verification.Click += new EventHandler(Verification_Click);
                    // Update display
                    panel.Children.RemoveAt(1);
                    panel.Children.Add(Verification);
                    panel.Children.Add(Corrupt);
                    break;
                // If none of the above, assume that error occured and exit application
                default:
                    pinText.TextContent = "Error. Exiting Application";
                    break;
            }

        }
        #endregion
    }
}